﻿/*
 *	Copyright (c) 2009 Queensland University of Technology. All rights reserved.
 *	The QUT Bioinformatics Collection is open source software released under the 
 *	Microsoft Public License (Ms-PL): http://www.microsoft.com/opensource/licenses.mspx.
 */
// <copyright file="SilverMapController.xaml.cs" company="QUT">
//  Copyright (c) Queensland University of Technology.  All rights reserved.
// </copyright>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace QUT.Bio.SilverMap.ObjectModel {
	
	/// <summary>
	/// A DefaultFeature represents an aligned subsequence identified by an alignment tool.
	/// <para>
	/// First arises from BLAST HSPs, but should also be useable in conjunction with other
	/// alignment programs, such as ClustalW, and also with Motif representations. But that 
	/// comes later.
	/// </para>
	/// </summary>

	public class DefaultFeature: IFeature, IComparable {
		#region Variables
		private ILinearDomain containingSequence;
		private long start; 
		private long end;
		private string sequenceData;
		#endregion

		#region Constructor
		/// <summary>
		/// Initialises this feature, passing sequenceSummary attributes thru to sequenceSummary constructor 
		/// and saving start and end.
		/// </summary>
		/// <param name="containingSequence">A reference to the containing sequence </param>
		/// <param name="start">The start position of this feature relative to its containing entity.</param>
		/// <param name="end">The end position of this feature relative to its containing entity.</param>
		/// <param name="subsequence">The actual character data associated with this feature, if available.</param>
		
		public DefaultFeature (
			ILinearDomain containingSequence,
			long start,
			long end,
			string subsequence
		) {
			if (containingSequence == null) {
				throw new ArgumentException( "Containing sequence may not be null." );
			}
			
			this.containingSequence = containingSequence;
			this.start = start;
			this.end = end;
			this.sequenceData = subsequence;
		} 
		#endregion

		#region Method: CompareTo
		/// <summary>
		/// Compare this Feature to another, in order of containing sequence id, start, end, and finally sequenceData.
		/// </summary>
		/// <param name="obj">A feature to be compared against.</param>
		/// <returns>
		///		less than 0 if this feature ranks "before"; 
		///		0 if the two features reference the same location; 
		///		greater than 0 if this feature ranks after the other
		///	</returns>
		///	<exception cref="ArgumentException">Argument exception is thrown if obj is not a Feature.</exception>

		public int CompareTo ( object obj ) {
			if ( ! ( obj is DefaultFeature ) ) {
				throw new ArgumentException( "Compared object must be a DefaultFeature." );
			}

			DefaultFeature other = (DefaultFeature) obj;
			
			int result = this.containingSequence.CompareTo( other.containingSequence );
			
			if ( result == 0 ) {
				result = start.CompareTo( other.start );
			} 
			
			if ( result == 0 ) {
				result = end.CompareTo( other.end );
			}
			
			if ( result == 0 ) {
				result = this.sequenceData.CompareTo( other.SequenceData );
			}
			
			return result;
		}
		#endregion

		#region Method: Equals
		/// <summary>
		/// Compares this Feature to an arbitrary object for equality.
		/// </summary>
		/// <param name="obj">An object against which this feature is to be compared.</param>
		/// <returns>
		///		true if and only if the other object is a Feature with GI, start and end
		///		equal to those of this feature.
		/// </returns>
		
		public override bool Equals ( object obj ) {
			if ( obj is DefaultFeature ) {
				return 0 == CompareTo( (DefaultFeature) obj );
			}
			else {
				return false;
			}
		}
		#endregion
		
		#region Method: GetHashCode
		/// <summary>
		/// A (probably not especially good) override of GetHashCode that is consistent with Equals.
		/// </summary>
		/// <returns>An integer such that, if Feature x equals Feature y, x.GetHashCode() = y.GetHashCode().</returns>
		
		public override int GetHashCode () {
			return ( ( containingSequence.GetHashCode() << 5 + (int) start ) << 5 + (int) end ) << 5 + sequenceData.GetHashCode();
		}
		#endregion

		#region Property: ContainingSequence
		/// <summary>
		/// Gets a reference to the underlying sequence of which this feature is a part.
		/// The underlying sequence may be an abstraction; it may not have any character 
		/// data associated with it.
		/// </summary>

		public ILinearDomain ContainingSequence {
			get {
				return containingSequence;
			}
		} 
		#endregion

		#region Property: Start
		/// <summary>
		/// Gets the start of this Feature.
		/// </summary>

		public long Start {
			get {
				return start;
			}
		}
		#endregion

		#region Property: End
		/// <summary>
		/// Gets the end of this Feature.
		/// </summary>

		public long End {
			get {
				return end;
			}
		}
		#endregion
		
		#region Property: SequenceData
		/// <summary>
		/// Gets the actual sequence data 
		/// </summary>
		
		public string SequenceData {
			get {
				return sequenceData;
			}
		}
		#endregion
	}
}
